package com.warm.pump.executor;

import com.alibaba.fastjson.JSON;

import com.warm.pump.executor.service.BaseExecService;
import com.warm.pump.frame.db.DbUtil;
import com.warm.pump.frame.gen.util.TypeCast;
import com.warm.pump.frame.util.DateUtils;
import com.warm.pump.frame.util.IpUtil;
import com.warm.pump.frame.util.SeqnumBuilder;
import com.warm.pump.frame.util.SpringBeanUtil;
import com.warm.pump.module.monitor.bean.po.gen.MisfireInform;
import com.warm.pump.module.monitor.bean.po.gen.MonitorCache;
import com.warm.pump.module.monitor.dao.gen.MisfireInformDao;
import com.warm.pump.module.monitor.dao.gen.MonitorCacheDao;
import com.warm.pump.module.monitor.inform.InformModeEnum;
import com.warm.pump.module.monitor.inform.InformModeWrapper;
import com.warm.pump.module.skd.bean.po.gen.*;
import com.warm.pump.module.skd.dao.gen.*;
import com.warm.pump.module.work.bean.po.gen.Work;
import com.warm.pump.module.work.bean.po.gen.WorkItem;
import com.warm.pump.module.work.bean.po.gen.WorkParams;
import com.warm.pump.module.work.dao.gen.WorkDao;
import com.warm.pump.module.work.dao.gen.WorkItemDao;
import com.warm.pump.module.work.dao.gen.WorkParamsDao;
import com.warm.pump.module.work.dao.gen.WorkSubjectDao;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.*;

@Service
public class InstanceService {
    private final Logger logger = LoggerFactory.getLogger(getClass());
    @Autowired
    private WorkDao workDao;
    @Autowired
    private WorkItemDao workItemDao;
    @Autowired
    private ScheduleInstanceDao scheduleInstanceDao;
    @Autowired
    private ScheduleInstanceDtlDao scheduleInstanceDtlDao;
    @Value("${server.port}")
    private Integer port;
    @Autowired
    private WorkParamsDao workParamsDao;

    @Autowired
    private JobLauncher jobLauncher;
    @Autowired
    private ScheduleLogDao scheduleLogDao;
    @Autowired
    private ScheduleWaitRunBoDao scheduleWaitRunBoDao;
    @Autowired
    private MonitorCacheDao monitorCacheDao;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private MisfireInformDao misfireInformDao;


    /**
     * 运行实例
     *
     * @param waitRunInstance
     */
    public void runInstance(ScheduleInstance waitRunInstance) {
        //设置处理任务数 默认为5
        int dealTaskNum = 5;
        if (waitRunInstance.getDealTaskNum() != null && waitRunInstance.getDealTaskNum() > 0) {
            dealTaskNum = waitRunInstance.getDealTaskNum();
        }
        //判断服务器是否 单线程执行
        if (waitRunInstance.getIsSingle() != null && waitRunInstance.getIsSingle() == 1) {
            dealTaskNum = 1;
//            //判断执行机器ip和第一次执行的ip是否相同，若不相同退出 不执行
//            if (org.apache.commons.lang.StringUtils.isNotEmpty(waitRunInstance.getExecIp()) && !waitRunInstance.getExecIp().equals(IpUtil.getIpPort(port))) {
//                logger.debug("调度任务实例{},为单线程实例，只能在第一次执行ip{}上执行", waitRunInstance.getInstanceId(), waitRunInstance.getExecIp());
//                return;
//            }
            //判断是否有正在执行的实例
            List<ScheduleInstanceDtl> runIngTaskList = this.getRunIngTaskList(waitRunInstance.getInstanceId());

            if (null != runIngTaskList && runIngTaskList.size() > 0) {
                logger.debug("调度任务实例{},为单线程实例,正在运行的实现id{}", waitRunInstance.getInstanceId(), runIngTaskList.get(0).getId());
                return;
            }
        }

        //通过实例id获取待处理的实例明细
        List<ScheduleInstanceDtl> waitRunTaskList = this.getWaitRunInstDtlList(waitRunInstance.getInstanceId(), dealTaskNum);
        if (null == waitRunTaskList || waitRunTaskList.size() == 0) {
            logger.debug("任务实例{},没有可运行的任务", waitRunInstance.getInstanceId());
            return;
        }

        //放到任务池中执行
        //后期把常量放到配置文件中
        // 任务开始时间
        long startTime = System.currentTimeMillis();
        ExecutorService service = Executors.newFixedThreadPool(dealTaskNum);
        List<Future> list = new ArrayList<>();
        for (ScheduleInstanceDtl instDtl : waitRunTaskList) {
            Future<?> future = service.submit(() -> {
                this.executeInstDtl(instDtl);
                //更新调度任务实例状态
                this.dealInstStatus(waitRunInstance);
            });
            list.add(future);
        }

        //关闭线程池
        service.shutdown();
        //通过Future可以并发发出N个请求，然后等待最慢的一个返回
        for (Future future : list) {
            try {
                future.get();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        // 任务执行总时长
        long times = System.currentTimeMillis() - startTime;
        logger.debug(times + "");

    }

    public List<ScheduleInstance> getNoCompletedInst(List<Integer> statusList, boolean isLocal) {
        List<ScheduleInstance> instList = new ArrayList<>();
        Map<String, Object> condMap = new HashMap<>();
        condMap.put("status_in", statusList);
        if (isLocal) {
            condMap.put("execIp", IpUtil.getIpPort(port));
        }
        condMap.put("orderBy", "create_time");
        List<ScheduleInstance> runingList = scheduleInstanceDao.getListByMap(condMap);
        if ( null == runingList ||runingList.size() < 1) {
            return null;
        }
        for (ScheduleInstance inst : runingList) {
            if (null != inst) {
                ScheduleInstance scheduleInstance = dealInstStatus(inst);
                if (null != scheduleInstance) {
                    instList.add(scheduleInstance);
                }
            }
        }
        if(instList.size()==0){
            return null;
        }

        return instList;
    }


    /**
     * 执行实例明细
     *
     * @param instanceDtl
     */
    public void executeInstDtl(ScheduleInstanceDtl instanceDtl) {
        //1.判断实例明细是否可以执行
        //2.获取实例明细 关联 作业 执行参数
        String params = instanceDtl.getParams();
        Map<String, Object> condValueMap =null;
        if (params != null) {
            condValueMap = JSON.parseObject(params);
        }
        //3.判断作业明细Id是否为空，若为空 则执行该关联作业所有状态为正常的所有明细
        // 若不为空 则只执行该作业明细
        //错误信息
        String taskErrMsg = "";
        //作业明细处理数
        int succNum = 0;
        //作业明细失败数
        int errNum = 0;
        //作业明细数
        int totalNum ;

        if (null != instanceDtl.getWorkItemId()) {
            totalNum = 1;
        } else {
            Map<String, Object> dtlCondMap = new HashMap<>();
            dtlCondMap.put("itemId", instanceDtl.getWorkItemId());
            dtlCondMap.put("status", 1);
            totalNum = workItemDao.countTotalByMap(dtlCondMap);
        }
        //判断作业 是否指定参数执行
        Work work = workDao.selectByPrimaryKey(instanceDtl.getWorkId());
        Long paramsId = work.getParamsId();

        if(null != paramsId){
            WorkParams workParams = workParamsDao.selectByPrimaryKey(paramsId);
            if(null != workParams){
                Integer paramsType = workParams.getType();
                //参数类型为list，循环list执行
                if (paramsType == 3) {
                    List<Map<String, Object>> list = DbUtil.findList(workParams.getDbKey(), workParams.getParamValue());
                    for (Map<String, Object> map : list) {
                        condValueMap = map;
                        taskErrMsg += dealWorkItem(instanceDtl,condValueMap);
                    }
                    //参数类型为sql
                }else if (paramsType == 2){
                    Map<String, Object> ones = DbUtil.findOne(workParams.getDbKey(), workParams.getParamValue());
                    condValueMap = new HashMap<>();
                    for(Map.Entry<String,Object> one : ones.entrySet()){
                        condValueMap.put(one.getKey(), TypeCast.getObjectWithDateFormat(one.getValue()));
                    }
                    taskErrMsg += dealWorkItem(instanceDtl,condValueMap);
                    //参数类型为值
                }else if (paramsType == 1){
                    condValueMap = new HashMap<>();
                    condValueMap.put(workParams.getParamKey(), TypeCast.getObjectWithDateFormat(workParams.getParamValue()));
                    taskErrMsg +=dealWorkItem(instanceDtl,condValueMap);
                }
            }else{
                dealWorkItem(instanceDtl,condValueMap);
            }
        }else {
            dealWorkItem(instanceDtl,condValueMap);
        }


        try{
            if(redisTemplate.hasKey("workParams" + instanceDtl.getWorkId())){
                //清空redis中关于参数的存储
                redisTemplate.delete("workParams" + instanceDtl.getWorkId());
            }
        }catch (Exception e){
            logger.error("redis删除[{}]失败，具体错误信息为:{}","workParams" + instanceDtl.getWorkItemId(),e.getMessage());
        }

        Map<String, Object> logMap = new HashMap<>();
        logMap.put("instanceId",instanceDtl.getInstanceId());
        logMap.put("instanceDtlId",instanceDtl.getId());
        logMap.put("workItemId",instanceDtl.getWorkItemId());
        List<ScheduleLog> skdLogs = scheduleLogDao.getListByMap(logMap);

        for (ScheduleLog skdLog:skdLogs) {
            if (2 == skdLog.getStatus()) {
                taskErrMsg += "错误日志ID[" + skdLog.getId() + "]/n";
                errNum++;
            } else {
                succNum++;
            }
        }


        //4.更新实例任务状态 为完成
        ScheduleInstanceDtl updateInstDtl = new ScheduleInstanceDtl();
        updateInstDtl.setId(instanceDtl.getId());
        updateInstDtl.setRunStatus(4);
        updateInstDtl.setUpdateTime(new Date());
        updateInstDtl.setTotalNum(totalNum);
        updateInstDtl.setSuccNum(succNum);
        updateInstDtl.setErrNum(errNum);
        updateInstDtl.setError(taskErrMsg);
        scheduleInstanceDtlDao.updateByPrimaryKeySelective(updateInstDtl);

        //5.根据失败策略 进行处理
        // 查询执行日志，若有失败信息，把失败信息 按照配置的失败策略

    }

    private String dealWorkItem(ScheduleInstanceDtl instanceDtl,Map<String, Object> condValueMap){
        String taskErrMsg = "";
        if (null != instanceDtl.getWorkItemId()) {
            WorkItem itemDtl = workItemDao.selectByPrimaryKey(instanceDtl.getWorkItemId());
            execItemDtl(instanceDtl, itemDtl, condValueMap);
        } else {
            Map<String, Object> dtlCondMap = new HashMap<>();
            dtlCondMap.put("workId", instanceDtl.getWorkId());
            dtlCondMap.put("status",1);
            dtlCondMap.put("orderBy", "exec_num");
            List<WorkItem> itemDtlList = workItemDao.getListByMap(dtlCondMap);

            //按顺序号 分组
            Map<Integer, List<WorkItem>> execMap = new LinkedHashMap<>();
            for (WorkItem itemDtl : itemDtlList) {
                if (execMap.containsKey(itemDtl.getExecNum())) {
                    execMap.get(itemDtl.getExecNum()).add(itemDtl);
                } else {
                    List<WorkItem> dtlList = new ArrayList<>();
                    dtlList.add(itemDtl);
                    execMap.put(itemDtl.getExecNum(), dtlList);
                }
            }

            //按顺序号执行
            for (Map.Entry<Integer, List<WorkItem>> numEtls : execMap.entrySet()) {
                ExecutorService service = Executors.newFixedThreadPool(3);
                List<Future> list = new ArrayList<>();
                for (WorkItem dtl : numEtls.getValue()) {
                    Map<String, Object> finalCondValueMap = condValueMap;
                    Future<String> future = service.submit(() -> {
                        String errMsg = "";
                        try {
                            execItemDtl(instanceDtl, dtl, finalCondValueMap);
                        } catch (Exception e) {
                            errMsg = e.getMessage();
                        }
                        return errMsg;
                    });

                    list.add(future);
                }

                //关闭线程池
                service.shutdown();

                //通过Future可以并发发出N个请求，然后等待最慢的一个返回
                for (Future future : list) {
                    try {
                        taskErrMsg += future.get();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (ExecutionException e) {
                        e.printStackTrace();
                    }
                }

            }
        }
        return taskErrMsg;
    }

    /**
     * 处理实例状态，若存在待执行的任务 返回该实例
     *
     * @param inst
     * @return
     */
    @Transactional
    public ScheduleInstance dealInstStatus(ScheduleInstance inst) {
        Map<String, Object> instCondMap = new HashMap<>();
        instCondMap.put("id", inst.getId());
        Map<String, Object> instanceMap = scheduleWaitRunBoDao.getInstByIdForUpdate(instCondMap);

        if (null == instanceMap || instanceMap.size() == 0) {
            return null;
        }
        Integer status = inst.getStatus();
        //如果状态等于4，则返回空
        if (4 == status) {
            return null;
        }
        //判断下所有实例任务 是否都已完成
        Map<String, Object> statusCondMap = new HashMap<>();
        statusCondMap.put("instanceId", inst.getInstanceId());
        Map<String, Object> taskStatusNumMap = scheduleWaitRunBoDao.getInstDtlStatusNum(statusCondMap);
        if (null == taskStatusNumMap || taskStatusNumMap.size() == 0) {
            return null;
        }
        //所有任務数
        int totalNum = TypeCast.getInteger(taskStatusNumMap.get("total_num"));
        //完成的任务数
        int completedNum = TypeCast.getInteger(taskStatusNumMap.get("completed_num"));
        //再运行的任务数
        int waitum = TypeCast.getInteger(taskStatusNumMap.get("wait_num"));
        //1.任务数等于0 返回空
        if (totalNum == 0) {
            ScheduleInstance instance = new ScheduleInstance();
            instance.setId(inst.getId());
            instance.setStatus(4);
            instance.setUpdateTime(new Date());
            instance.setRemark("实例任务为空");
            scheduleInstanceDao.updateByPrimaryKeySelective(instance);
            return null;
        }
        //2.所有任務数=完成的任务数 更新任务实例为已完成 返回空
        if (totalNum == completedNum) {
            ScheduleInstance instance = new ScheduleInstance();
            instance.setId(inst.getId());
            instance.setStatus(4);
            instance.setUpdateTime(new Date());
            instance.setCompletedNum(completedNum);
            instance.setWaitNum(0);
            scheduleInstanceDao.updateByPrimaryKeySelective(instance);


            //根据任务实例中的失败策略 进行失败预警处理
            if(StringUtils.isNotEmpty(inst.getMisfireInformIds())){
                dealMisfire(inst);
            }

            return null;
        }
        //3.若存在待执行的任务 返回该实例
        if (waitum > 0) {
            ScheduleInstance instance = new ScheduleInstance();
            instance.setId(inst.getId());
            instance.setUpdateTime(new Date());
            instance.setCompletedNum(completedNum);
            instance.setWaitNum(waitum);
            instance.setStatus(3);
            //只记录第一次执行的ip
            instance.setExecIp(org.apache.commons.lang.StringUtils.isEmpty(inst.getExecIp()) ? IpUtil.getIpPort(port) : inst.getExecIp());
            scheduleInstanceDao.updateByPrimaryKeySelective(instance);
            return inst;
        }

        return null;
    }

    /**
     * 处理任务失败预警
     * @param inst
     */
    private void dealMisfire(ScheduleInstance inst){
        Thread th = new Thread(() -> {
            Map<String, Object> logMap = new HashMap<>();
            logMap.put("instanceId",inst.getInstanceId());
            Map<String,Object> instState = scheduleWaitRunBoDao.getInstRunState(logMap);
            int failure = TypeCast.getInteger(instState.get("failure"));
            int successful = TypeCast.getInteger(instState.get("successful"));
            int total = TypeCast.getInteger(instState.get("total"));
            int level1Num = TypeCast.getInteger(instState.get("level1Num"));
            int level2Num = TypeCast.getInteger(instState.get("level2Num"));
            int level3Num = TypeCast.getInteger(instState.get("level3Num"));
            if(failure>0){
                String[] failureDeals = inst.getMisfireInformIds().split(",");
                String sendContent = "实例ID["+inst.getInstanceId()+"],处理任务"+inst.getReferName()+"["+inst.getReferId()+"],共"+total+",成功"+successful+"失败"+failure
                        +",其中失败作业中,紧急"+level1Num+"重要"+level2Num+"一般"+level3Num;
                for (String failureDeal:failureDeals) {
                    MisfireInform workFailureDeal = misfireInformDao.selectByPrimaryKey(TypeCast.getLong(failureDeal));
                    InformModeWrapper noticeMode = InformModeEnum.match(workFailureDeal.getInformMode(), InformModeEnum.DINGDING);
                    noticeMode.send(workFailureDeal,sendContent,"作业任务失败预警");
                }
            }
        });
        th.setDaemon(true);
        th.start();
    }

    /**
     * 根据实例Id获取 待执行的实例明细
     *
     * @param instanceId
     * @param dealTaskNum
     * @return
     */
    @Transactional
    public List<ScheduleInstanceDtl> getWaitRunInstDtlList(String instanceId, int dealTaskNum) {
        Map<String, Object> runCondMap = new HashMap<>();
        runCondMap.put("instanceId", instanceId);
        runCondMap.put("dealTaskNum", dealTaskNum);
        runCondMap.put("waitTime", DateUtils.addDateMin(new Date(), -1));
        List<Map<String, Object>> waitRunTask = scheduleWaitRunBoDao.getWaitRunInstDtl(runCondMap);

        if (null == waitRunTask || waitRunTask.size() == 0) {
            logger.debug("任务实例{},没有可运行的任务", instanceId);
            return null;
        }

        List<Long> idList = new ArrayList<>();
        for (Map<String, Object> taskMap : waitRunTask) {
            long id = TypeCast.getLong(taskMap.get("id"));
            ScheduleInstanceDtl instanceTask = new ScheduleInstanceDtl();
            instanceTask.setId(id);
            instanceTask.setRunStatus(3);
            instanceTask.setUpdateTime(new Date());
            instanceTask.setExecIp(IpUtil.getIpPort(port));
            scheduleInstanceDtlDao.updateByPrimaryKeySelective(instanceTask);
            idList.add(id);
        }

        Map<String, Object> condMap = new HashMap<>();
        condMap.put("id_in", idList);
        return scheduleInstanceDtlDao.getListByMap(condMap);
    }

    /**
     * 获取正在运行的任务列表
     *
     * @param instanceId
     * @return
     */
    private List<ScheduleInstanceDtl> getRunIngTaskList(String instanceId) {
        Map<String, Object> runCondMap = new HashMap<>();
        runCondMap.put("instanceId", instanceId);
        runCondMap.put("runStatus", 3);
        List<ScheduleInstanceDtl> runIngTask = scheduleInstanceDtlDao.getListByMap(runCondMap);
        return runIngTask;
    }

    /**
     * 执行作业明细
     *
     * @param instanceDtl
     * @param itemDtl
     * @param condValueMap
     */
    private void execItemDtl(ScheduleInstanceDtl instanceDtl, WorkItem itemDtl, Map<String, Object> condValueMap) {
        //判断是bean模式还是Sql模式
        String mode = itemDtl.getDetailMode();

        if (StringUtils.isNotEmpty(mode)) {
            //bean模式
            if ("BEAN_M".equals(mode)) {
                execItemDtlBEANM(instanceDtl, itemDtl, condValueMap);
            }
            //Sql模式
            else if ("SQL_M".equals(mode)||"REDIS_M".equals(mode)) {
                execItemDtlSQlM(instanceDtl, itemDtl, condValueMap);
            }
        }
    }

    /**
     * 作业项执行模式 bean模式 BEAN_M
     *
     * @param instanceDtl
     * @param itemDtl
     * @param condValueMap
     */
    private void execItemDtlBEANM(ScheduleInstanceDtl instanceDtl, WorkItem itemDtl, Map<String, Object> condValueMap) {
        ScheduleLog skdLog = new ScheduleLog();
        skdLog.setInstanceId(instanceDtl.getInstanceId());
        skdLog.setInstanceDtlId(instanceDtl.getId());
        skdLog.setWorkItemId(instanceDtl.getWorkItemId());
        skdLog.setWorkItemName(instanceDtl.getWorkItemName());
        skdLog.setWorkItemId(itemDtl.getId());
        skdLog.setWorkItemName(itemDtl.getItemName());
        skdLog.setStatus(1);
        skdLog.setRemark("执行中");
        skdLog.setStartTime(new Date());
        skdLog.setRemark("beanName:" + itemDtl.getBeanName() + ",methodName:exec,params:" + JSON.toJSONStringWithDateFormat(condValueMap, "yyyy-MM-dd HH:mm:ss"));

        scheduleLogDao.insertSelective(skdLog);

        String errFormat = "调度实例%s,作业%s[%s],作业明细%s[%s]执行时报错，错误原因为:%s";
        try {

            if (StringUtils.isEmpty(itemDtl.getBeanName())) {
                String errMsg = String.format(errFormat, instanceDtl.getInstanceId(), instanceDtl.getWorkItemName(), instanceDtl.getWorkItemId(),
                        itemDtl.getItemName(), itemDtl.getId(), "执行模式为空(work_item_dtl.bean_name)");
                throw new RuntimeException(errMsg);
            }

            BaseExecService processService = SpringBeanUtil.getBean(itemDtl.getBeanName());
            processService.initParams(instanceDtl, itemDtl, condValueMap);
            processService.exec();
            ScheduleLog updateLog = new ScheduleLog();
            updateLog.setId(skdLog.getId());
            updateLog.setStatus(3);
            updateLog.setUpdateTime(new Date());
            scheduleLogDao.updateByPrimaryKeySelective(updateLog);
        } catch (Exception e) {
            String errMsg = String.format(errFormat, instanceDtl.getInstanceId(), instanceDtl.getWorkItemName(), instanceDtl.getWorkItemId(),
                    itemDtl.getItemName(), itemDtl.getId(), e.getMessage());
            skdLog.setStatus(2);
            skdLog.setEndTime(new Date());
            skdLog.setError(errMsg);
            scheduleLogDao.updateByPrimaryKeySelective(skdLog);
            throw new RuntimeException(errMsg);
        }


    }

    /**
     * 调用spring batch 执行调度实例   作业项执行模式 sql模式 SQL_M
     *
     * @param instanceDtl
     * @param itemDtl
     * @param condValueMap
     */
    private void execItemDtlSQlM(ScheduleInstanceDtl instanceDtl, WorkItem itemDtl, Map<String, Object> condValueMap) {
        try {
            JobParametersBuilder jobParametersBuilder = new JobParametersBuilder();
            jobParametersBuilder.addDate("date", new Date());
            jobParametersBuilder.addLong("itemId", itemDtl.getId());
            jobParametersBuilder.addLong("instDtlId", instanceDtl.getId());
            jobParametersBuilder.addString("params", JSON.toJSONStringWithDateFormat(condValueMap, "yyyy-MM-dd HH:mm:ss"));
            JobParameters parameters = jobParametersBuilder.toJobParameters();
            String mode = itemDtl.getDetailMode();
            Job job = null;
            if("SQL_M".equals(mode)){
                job = SpringBeanUtil.getBean("sqlJob");
            }
            else if("REDIS_M".equals(mode)){
                job = SpringBeanUtil.getBean("redisJob");

                if("REDIS_M".equals(itemDtl.getDetailMode())){
                    //判断是否有再用的缓存 更新失效时间

                    Map<String,Object> condMap = new HashMap<>();
                    condMap.put("startDate_lessEqual",new Date());
                    condMap.put("expireDate_greaterEqual",new Date());
                    condMap.put("cacheName",itemDtl.getCacheName());
                    List<MonitorCache> oldCacheList = monitorCacheDao.getListByMap(condMap);
                    if(null != oldCacheList&&oldCacheList.size()>0){
                        for (MonitorCache oldCache:oldCacheList) {
                            oldCache.setExpireDate(new Date());
                            monitorCacheDao.updateByPrimaryKeySelective(oldCache);
                        }
                    }

                    MonitorCache cache = new MonitorCache();
                    cache.setCacheName(itemDtl.getCacheName());
                    cache.setStartDate(new Date());
                    cache.setExpireDate(DateUtils.addDateSec(new Date(), TypeCast.getInteger(itemDtl.getExpireTime())));
                    monitorCacheDao.insertSelective(cache);
                }
            }


            //由于高并发下spring batch 创建batch_job_instance时报死锁问题 进而添加容错机制，
            try {
                JobExecution result = jobLauncher.run(job, parameters);
            } catch (Exception e) {
                e.printStackTrace();
                logger.error(e.getMessage());
                Thread.sleep(TypeCast.getInteger(100 * Math.random()));
                try {
                    JobExecution result = jobLauncher.run(job, parameters);
                } catch (Exception e1) {
                    e.printStackTrace();
                    logger.error(e.getMessage());
                    Thread.sleep(TypeCast.getInteger(400 * Math.random()));
                    try {
                        JobExecution result = jobLauncher.run(job, parameters);
                    } catch (Exception e2) {
                        e.printStackTrace();
                        logger.error(e.getMessage());
                        Thread.sleep(TypeCast.getInteger(800 * Math.random()));
                        try {
                            JobExecution result = jobLauncher.run(job, parameters);
                        } catch (Exception e3) {
                            e.printStackTrace();
                            logger.error(e.getMessage());
                            Thread.sleep(TypeCast.getInteger(10000 * Math.random()));
                            JobExecution result = jobLauncher.run(job, parameters);
                        }
                    }

                }
            }

        } catch (Exception e) {
            String errMsg = String.format("调度实例%s,作业%s[%s],作业明细%s[%s]执行时报错，错误原因为:%s", instanceDtl.getInstanceId(), instanceDtl.getWorkItemName(), instanceDtl.getWorkItemId(),
                    itemDtl.getItemName(), itemDtl.getId(), e.getMessage());
            logger.error(errMsg);
            e.printStackTrace();

            throw new RuntimeException(errMsg);
        }

    }

    /**
     * 创建调度实例
     * @param referType
     * @param referId
     * @param referName
     * @param totalNum
     * @param remark
     * @param misfireInformIds
     * @return
     */
    public String createInst(String referType, Long referId, String referName, Integer totalNum, String remark,String misfireInformIds) {
        ScheduleInstance inst = new ScheduleInstance();

        String instanceId = DateUtils.getDataString(DateUtils.yyyymmddhhmmss) + referId + SeqnumBuilder.getFixedSeqnum(3);
        inst.setInstanceId(instanceId);
        inst.setReferType(referType);
        inst.setReferId(referId);
        inst.setReferName(referName);
        inst.setStatus(1);
        inst.setRemark(remark);
        inst.setTotalNum(totalNum);
        inst.setCompletedNum(0);
        inst.setWaitNum(0);
        inst.setCreateTime(new Date());
        inst.setUpdateTime(new Date());
        inst.setCreateIp(IpUtil.getIpPort(port));
        inst.setIsSingle(1);
        inst.setMisfireInformIds(misfireInformIds);
        scheduleInstanceDao.insertSelective(inst);

        return instanceId;
    }


    /**
     * 创建调度实例
     *
     * @param referType
     * @param referId
     * @param referName
     * @param totalNum
     * @param remark
     * @return
     */
    public String createInst(String referType, Long referId, String referName, Integer totalNum, String remark) {
        return this.createInst(referType,referId,referName,totalNum,remark,null);
    }

    /**
     * 创建实例明细
     *
     * @param instId
     * @param workId
     * @param workName
     * @param itemDtlId
     * @param itemDtlname
     * @param params
     */
    public void createInstDtl(String instId, Long workId, String workName, Long itemDtlId, String itemDtlname, String params) {
        ScheduleInstanceDtl instDtl = new ScheduleInstanceDtl();
        instDtl.setInstanceId(instId);
        instDtl.setWorkId(workId);
        instDtl.setWorkName(workName);
        instDtl.setWorkItemId(itemDtlId);
        instDtl.setWorkItemName(itemDtlname);
        instDtl.setParams(params);
        instDtl.setRunStatus(1);

        if (null == itemDtlId) {
            Map<String, Object> dtlMap = new HashMap<>();
            dtlMap.put("workId", workId);
            dtlMap.put("status", 1);
            int dtlCnt = workItemDao.countTotalByMap(dtlMap);
            instDtl.setTotalNum(dtlCnt);
        } else {
            instDtl.setTotalNum(1);
        }
        instDtl.setSuccNum(0);
        instDtl.setErrNum(0);
        instDtl.setCreateTime(new Date());
        instDtl.setUpdateTime(new Date());
        scheduleInstanceDtlDao.insertSelective(instDtl);
    }

    /**
     * 获取参数
     *
     * @return
     */
    public Map<String, Object> getParamsMap(Long workId) {
        String redisKey = "workParams" + workId;
        Map<String, Object> rtMap = (Map<String, Object>) redisTemplate.opsForValue().get(redisKey);
        if(rtMap == null ||rtMap.size()<1){
            try {
                //先获取公共参数
                Map<String, Object> condMap = new HashMap<>();
                condMap.put("belongType", "1");
                List<WorkParams> workParams = workParamsDao.getListByMap(condMap);

                //获取该任务的私有参数
                Map<String, Object> taskCondMap = new HashMap<>();
                taskCondMap.put("belongType", "2");
                taskCondMap.put("belongId", workId);
                List<WorkParams> taskItemParams = workParamsDao.getListByMap(taskCondMap);

                workParams.addAll(taskItemParams);

                rtMap = new HashMap<>();
                for (WorkParams param : workParams) {
                    if (param.getType() == 2) {
                        Map<String, Object> ones = DbUtil.findOne(param.getDbKey(), param.getParamValue());
                        for (Map.Entry<String, Object> one : ones.entrySet()) {
                            rtMap.put(one.getKey(), TypeCast.getObjectWithDateFormat(one.getValue()));
                        }
                    } else if (param.getType() == 1) {
                        rtMap.put(param.getParamKey(),TypeCast.getObjectWithDateFormat( param.getParamValue()));
                    }
                }
                redisTemplate.opsForValue().set(redisKey,rtMap);
                redisTemplate.expire(redisKey, 10*60 * 1000, TimeUnit.SECONDS);
            } catch (Exception e) {
                e.printStackTrace();
                logger.error(e.getMessage());
                throw new RuntimeException(e);
            }
        }
        return rtMap;
    }


}
